package cn.pugle.mianshi.elevator.v1;

import java.util.TreeSet;
import java.util.concurrent.BlockingQueue;
import java.util.concurrent.LinkedBlockingQueue;

/**
 * 电梯实例.
 * 包含控制电梯真实动的方法(打印而已), 以_开头为调用硬件, 以__开头为硬件回调
 * 接收manager指令.
 * <p> Created by tzp on 2017/9/13.
 */
public class Elevator implements Runnable {
    private String name;
    //    private final int capacity = 20;//可以装20人
    //    private int load = 0;//已经装了多少人
    //关于如何控制硬件的信息, 现在穿个simulator过来
    private SimulatorV2 simulator;


    //状态信息,状态信息要 同步
    private BlockingQueue<Directive> directiveQueue = new LinkedBlockingQueue<>();
    private int level = 0;//当前处于多少层. (从2层向3层走时, level为2)
    private boolean goUp = true;//当前方向
    private State state = State.STOP;//当前状态
    private TreeSet<Integer> targetLevels = new TreeSet<>();//目标层 去重排序的

    public Elevator(String name) {
        this.name = name;
        this.simulator = new SimulatorV2(this);
    }

    @Override
    public void run() {
        System.out.println(name + " Start");
        while (!Thread.interrupted()) {//这个循环主要处理收到的按钮消息
            try {
                Directive directive = directiveQueue.take();
                if (directive instanceof Directive.InnerDirective) {
                    _operating(Action.MOVE_DOWN, 1);//todo
                } else if (directive instanceof Directive.OuterDirective) {

                }
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
        }
    }


    //--控制硬件方法

    /**
     * 按钮指令callback
     */
    private void __directiveCallback(Directive directive) {
        try {
            directiveQueue.put(directive);
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
    }

    /**
     * 状态改变callback
     *
     * @param currentAction
     * @param level
     */
    private void __stateCallback(Action currentAction, int level) {
        this.level = level;
    }

    private void __doneCallback(Action currentAction, int targetLevel) {
        switch (currentAction) {
            case MOVE_UP:
            case MOVE_DOWN: {
                _operating(Action.OPEN_GATE, -1);
                break;
            }
            case OPEN_GATE: {
                _operating(Action.CLOSE_GATE, -1);
                break;
            }
            case CLOSE_GATE: {
                //todo
            }
        }
    }

    private void _operating(Action action, int targetLevel) {
        simulator.simulate(action, targetLevel);
    }

    /**
     * 模拟器, 用于产生硬件消息
     */
//    public static class Simulator implements Runnable {
//        private ExecutorService threadPool = Executors.newCachedThreadPool();
//
//        @Override
//        public void run() {
//
//        }
//
//        public void simulate(Elevator elevator, Action action, int targetLevel) {
//            double delay = 1000 + 4000 * Math.random();
//            threadPool.execute(() -> {
//                try {
//                    Thread.sleep((long) delay);
////                    elevator._stateCallback();
//                } catch (InterruptedException e) {
//                    System.out.println(elevator.name + " " + action.name() + " interrupted");
//                }
//            });
//        }
//    }
    public static class SimulatorV2 implements Runnable {
        private Elevator elevator;
        private Action currentAction;
        private int targetLevel;
        private volatile boolean isInterrupt = false;
        private Action newAction;
        private int newLevel;

        public SimulatorV2(Elevator elevator) {
            this.elevator = elevator;
            new Thread(this).start();
        }

        /**
         * @param targetLevel 对于开关门动作为-1
         */
        public synchronized void simulate(Action action, int targetLevel) {
            if (currentAction != null) {
                isInterrupt = true;
                this.newAction = action;
                this.newLevel = targetLevel;
            } else {
                this.currentAction = action;
                this.targetLevel = targetLevel;
                this.notifyAll();
            }
        }

        @Override
        public void run() {
            while (!Thread.interrupted()) {   //外层循环, 取指令
                try {
                    synchronized (this) {
                        if (currentAction == null) {    //当前没有指令, wait住
                            this.wait();
                        }
                    }
                    //取到指令
                    System.out.println("simulator for " + elevator.name + " " + currentAction.name() + "begin");
                    long beginTime = System.currentTimeMillis();//模拟执行时间
                    double delay = 1000 + (targetLevel == -1 ? 0 : 1000 * Math.random() * Math.abs(targetLevel - elevator.level));

                    //开始执行, 没执行完也没打断. 内层循环,每隔100ms报告状态
                    while (System.currentTimeMillis() - beginTime < delay && !isInterrupt) {
                        int l = (int) ((System.currentTimeMillis() - beginTime) / 1000);//走了几层了
                        elevator.__stateCallback(currentAction, elevator.level + l);
                        Thread.sleep(100);
                    }
                    synchronized (this) {
                        if (isInterrupt) {//是被打断的
                            System.out.println("simulator for " + elevator.name + " interrupted");
                            currentAction = newAction;
                            targetLevel = newLevel;
                            isInterrupt = false;
                        } else {//执行完了
                            elevator.__doneCallback(currentAction, targetLevel);
                            currentAction = null;
                        }
                    }
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }
            }
        }
    }

    /**
     * 电梯的动作
     */
    public enum Action {
        MOVE_UP,
        MOVE_DOWN,
        OPEN_GATE,
        CLOSE_GATE
    }

    /**
     * 电梯的状态
     */
    public enum State {
        STOP,
        MOVING
    }
}
